/*
    
*/

#ifndef __MINIUTIL_FRAME_LOGSERVICE_H__
#define __MINIUTIL_FRAME_LOGSERVICE_H__

#include <string>
#include <vector>
#include <set>
#include "miniutil/os_compatible.h"
#include "miniutil/tinyxml.h"
#include "miniutil/thread.h"
#include "miniutil/threadservice.h"
#include "miniutil/strutil.h"

namespace miniutil { namespace frame {

    struct LogmsgEnti
    {
        LogmsgEnti();
        unsigned int level;
        std::string logmsg;
        time_t logtm;
#ifdef WIN32
        DWORD threadid;
#else
        pthread_t threadid;
#endif
    };

   class Logger
   {
        public:
            static const unsigned int LOG_LEVEL_ALL = 0xffffffff;
            static const unsigned int LOG_LEVEL_ERROR = 0x1;
            static const unsigned int LOG_LEVEL_CRIT = 0x2;
            static const unsigned int LOG_LEVEL_WARN = 0x4;
            static const unsigned int LOG_LEVEL_DEBUG = 0x8;
            static const unsigned int LOG_LEVEL_TRACE = 0x10;
            static const unsigned int LOG_LEVEL_AUDIT = 0x20;
            static const unsigned int LOG_LEVEL_USER = 0x40;
        public:
            bool isEnabled(unsigned int);
            void enableLevel(unsigned int);
            void setLogLevel(unsigned int);

        public:
            Logger();
            virtual ~Logger(){}
            virtual int config(miniutil::tinyxml::TiXmlElement*);
            virtual int log(const LogmsgEnti&);
            virtual int log_impl(const std::string&) = 0;
        protected:
            virtual bool should_log(const std::string &){return true;}
	    protected:
		    unsigned int levels;
            bool bappendtm;
            bool bappendthread;
   };
   
   class ConsoleLogger:public Logger
   {
        public:
            virtual int config(miniutil::tinyxml::TiXmlElement*);
            virtual int log_impl(const std::string&);
    };
    
   class LocalFileLogger:public Logger
   {
        public:
            LocalFileLogger();
            virtual int config(miniutil::tinyxml::TiXmlElement*);
            virtual int log_impl(const std::string&);
            void setfilenmprefix(const std::string&);
        protected:
            virtual std::string generate_filenm();
        private:
            FILE* plogfile;
            int maxfilesize;
            int maxfilenum;
            std::string filenmprefix;
            std::string savedir;
            bool mbuseprocessid;
            bool mbusetime;

            int curfileidx;
            int curwritesize;
    };

    class TagInnLogger
    {
    public:
        TagInnLogger(const std::string &tags, Logger*, bool);
        ~TagInnLogger();
    public:
        std::set<std::string> mapplytags;
        bool bprinttag;
        Logger* plogimpl;
    };

   class AutoTagFileLogger:public Logger
   {
        public:
            AutoTagFileLogger();
            ~AutoTagFileLogger();
            virtual int config(miniutil::tinyxml::TiXmlElement*);
            virtual int log(const LogmsgEnti&);
            virtual int log_impl(const std::string&);
        private:
            std::set<std::string> msexcludetags;
            std::map<std::string, LocalFileLogger*> malllogers;
            std::string mconfigxml;

   };

   class TagFilesLogger:public Logger
   {

        public:
            TagFilesLogger();
            ~TagFilesLogger();
            virtual int config(miniutil::tinyxml::TiXmlElement*);
            virtual int log(const LogmsgEnti&);
            virtual int log_impl(const std::string&);
        public:
            std::vector<TagInnLogger*> allinnloggers;
   };

   class RemoteLoggerStub:public Logger
   {
        public:
            RemoteLoggerStub();
            virtual int config(miniutil::tinyxml::TiXmlElement*);
            virtual int log_impl(const std::string&) = 0;
        private:
            SOCKET remotesoc;
            std::string remoteaddress;
    };
        
    class LogService:public ThreadService
    {
        struct loggerenti
        {
            Logger* plog;
            std::string logclsnm;
        };

        public:
            static void InitService();
        public:
            LogService(unsigned int sleepms = 100);
            ~LogService();
            virtual int config(miniutil::tinyxml::TiXmlElement*);
            int log(int, const std::string&);
            virtual int WorkingTask();
        private:
            std::vector<loggerenti> vinploggers;
            std::vector<LogmsgEnti> vlogmsgs;
            miniutil::mutex logmtx;
    }; 

    extern LogService galoggservice;
    
    class autoentry_logger
    {
    public:
        autoentry_logger(const char* fn, const char* func, int line);
        ~autoentry_logger();
    private:
        std::string sfn, sfunc;
        int mline;
    #ifdef WIN32
        DWORD threadid;
    #else
        pthread_t threadid;
    #endif
    };
    
} }    


#define T_LOG(msgtag, ...) { \
    std::string logmsg = miniutil::strutil::format(__VA_ARGS__); \
    logmsg = std::string("[tag:")+msgtag+"]"+logmsg; \
    miniutil::frame::galoggservice.log(miniutil::frame::Logger::LOG_LEVEL_DEBUG, logmsg); \
    }

#define F_LOG(level, ...) {miniutil::frame::galoggservice.log(level, __VA_ARGS__);}
#define F_ERROR(...) {miniutil::frame::galoggservice.log(miniutil::frame::Logger::LOG_LEVEL_ERROR, miniutil::strutil::format(__VA_ARGS__)); }
#define F_CRTI(...) {miniutil::frame::galoggservice.log(miniutil::frame::Logger::LOG_LEVEL_CRIT, miniutil::strutil::format(__VA_ARGS__)); }
#define F_WARN(...) {miniutil::frame::galoggservice.log(miniutil::frame::Logger::LOG_LEVEL_WARN, miniutil::strutil::format(__VA_ARGS__)); }
#define F_DEBUG(...) {miniutil::frame::galoggservice.log(miniutil::frame::Logger::LOG_LEVEL_DEBUG, miniutil::strutil::format(__VA_ARGS__)); }
#define F_TRACE(...) {miniutil::frame::galoggservice.log(miniutil::frame::Logger::LOG_LEVEL_TRACE, miniutil::strutil::format(__VA_ARGS__)); }
#define F_USER(...) {miniutil::frame::galoggservice.log(miniutil::frame::Logger::LOG_LEVEL_USER, miniutil::strutil::format(__VA_ARGS__)); }

#define FAUTOENTRY \
    miniutil::frame::autoentry_logger log##__LINE__(__FILE__, __FUNCTION__, __LINE__); 


#define FENTRY                                                           \
do {                                                                    \
        F_TRACE("Process entered\n");                           \
} while (0)

#define FRETURN(RETURN__ret)                                                      \
do {                                                                    \
        F_TRACE("Process leaving (rc=%lu : %ld : %lx)\n",       \
               (long)RETURN__ret, (long)RETURN__ret, (long)RETURN__ret);\
        return RETURN__ret;                                             \
} while (0)

#endif
